App = window.App || (function () {
	var app = {};
	try {
		app.name = 'app';
		app.version = 1.12;
		app.emptyFn = function () { };
		app.config = {
			name: 'app',
			debug: false,
			baseUrl: ''
		};

		app.init = function (config) {
			app.extend(app.config, config);
			app.name = app.config.name;
			app.debug = app.config.debug;
			app.baseUrl = app.config.baseUrl;
			app.config.require = app.config.require || [];
			app.require(app.config.require, function () {
				app.isUndefined(app.config.ready) || app.config.ready();
				releaseReady();
			});
		};

		app.require = function (r, callback) {
			if (typeof r === 'string') {
				if (app[r]) {
					complete();
					return;
				}
				var url = toModuleUrl(r);
				loadScript(url, complete);
			} else {
				var count = r.length, req = [];
				for (var i = 0; i < count; i++) {
					if (app[r[i]]) continue;
					req.push(toModuleUrl(r[i]));
				}

				loadScripts(req, complete);
			}

			function complete() {
				app.isUndefined(callback) || callback();
			}
		};

		app.define = function (name, require, getObj) {
			if (app[name]) return;

			if (!app.isArray(require)) {
				getObj = require;
				require = [];
			}

			app.require(require, function () {
				app[name] = getObj();
			});
		};

		var onready = [], isready = false;
		app.ready = function (fn) {
			if (typeof fn === 'function') {
				isready ? setTimeout(fn, 0) : onready.push(fn);
			}
		};
		function releaseReady() {
			if (!isready) {
				isready = true;
				var l = onready.length;
				for (var i = 0; i < l; i++) onready[i]();
				onready = [];
			}
		}

		app.isUndefined = function (obj) {
			return typeof obj == 'undefined';
		};

		app.isArray = function (array) {
			return Object.prototype.toString.call(array) === '[object Array]';
		};

		app.isEmptyObject = function ( obj ) {
			for ( var name in obj ) {
				return false;
			}
			return true;
		}

		app.isSupported = function () {
			var Browser = function (b, v) { return { browser: b, version: v }; };
			var support = [new Browser('webkit', 8),
						   new Browser('firefox', 3.6),
						   new Browser('safari', 5),
						   new Browser('opera', 11),
						   new Browser('msie', 9),
						   new Browser('ipad', 0)];
			var result = false;

			$.each(support, function (i, item) {
				result = result || (bowser[item.browser] && bowser.version >= item.version);
			});

			return result && !bowser.mobile && Modernizr.canvas && Modernizr.websockets;
		};

		app.dom = {
			body: document.body,
			head: document.getElementsByTagName('head')[0],
			all: document.all
		};

		app.template = function(pattern) {
			return function (data) {
				var html = pattern;
				for (var x in data) {
					var re = "{{\\s?" + x + "\\s?}}";
					html = html.replace(new RegExp(re, "ig"), data[x]);
				}
				return html;
			};
		};

		app.extend = function (d, s) {
			for (var p in s) {
				if (s[p] && s[p].constructor &&
				 s[p].constructor === Object) {
					d[p] = d[p] || {};
					arguments.callee(d[p], s[p]);
				} else {
					d[p] = s[p];
				}
			}
			return d;
		};

		app.getVerificationToken = function() {
			return document.getElementById('__AjaxAntiForgeryForm').elements[0].value;
		};

		function toModuleUrl(module) {
			return module.indexOf('/') > -1 ? module : app.config.baseUrl
				+ 'modules/{module}.module{.min}.js'
				.replace('{module}', module)
				.replace('{.min}', App.config.debug ? '' : '.min');
		}

		function loadScripts(urls, callback) {
			if (app.isUndefined(urls) || urls.length == 0) {
				app.isUndefined(callback) || callback(true);
			} else {
				Ajax.getScripts(urls, callback);
			}
		};

		function loadScript(path, callback) {
			Ajax.getScript(path, callback);
		};

	} catch (e) {
		console.error('app.js', e);
	}
	return app;
})();